iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
自我挑戰組

複習 JavaScript 核心概念系列 第 20

[Day 20] 物件的傳參考特性、淺層複製和深層複製

  • 分享至 

  • xImage
  •  

第13天 有稍微提到物件(包括陣列、函式等)具有 傳參考(Pass by Reference) 特性,今天將對此做更深入的探討,並且介紹正確複製物件的方法,也就是 淺層複製(Shallow Copy)深層複製(Deep Copy)


物件的傳參考特性

我們已經知道將一個物件賦值給另一個變數時,實際上是將參考的記憶體位置傳遞給了新的變數,而不是將物件本身複製一份。也就是說,如果你修改了其中一個變數所指向的物件,另一個變數也會受到影響。

let a = '小明';
let b = '小明';

// 判斷結果為 true ,因為 a 和 b 是字串(原始型別)為傳值特性,且它們具有相同的值
if(a === b) { }

let c = { name: '小明' };
let d = { name: '小明' };

// 判斷結果為 false ,因為 c 和 d 是物件(物件型別)為傳參考特性,而它們參考不同的記憶體位置
if(c === d) { }

另外要知道的事,使用 const 宣告一個新的物件時,雖然無法改變該物件的值(參考的記憶體位置),但仍能更改裡面的屬性。

const person = { name: '王小明' };
person = { name: '王鮭魚' }; // 報錯
const person = { name: '王小明' };
person.name = '王鮭魚'; // 不會報錯

物件裡面的屬性的值如果放純值,此時它們具備傳值特性,所以修改這些屬性的值,不會影響到其他原本相同的值。

const here = 'Taipei';

const x = { city: here };
const y = { city: here };

console.log(x.city); // 輸出 'Taipei'
console.log(y.city); // 輸出 'Taipei'

x.city = 'Tainan';

console.log(x.city); // 輸出 'Tainan'
console.log(y.city); // 輸出 'Taipei'

物件裡面的屬性的值也可以放物件、陣列、函式等等,當然此時它們當然也具備傳參考特性,所以修改這些屬性的值,所有參考此屬性的地方也都會受到影響。

const here = { city: 'Taipei' };

const x = { area: here };
const y = { area: here };

console.log(x.area); // 輸出 'Taipei'
console.log(y.area); // 輸出 'Taipei'

x.area.city = 'Tainan';

console.log(x.area); // 輸出 'Tainan'
console.log(y.area); // 輸出 'Tainan'

另外,物件裡面的屬性值也可以參考到該物件本身(雖然實際開發時很少這樣做)。例如以下範例。

const a = { x: 123 };
a.y = a;

// 判斷結果為 true,因為 a.y 和 a.y.y 其實都是參考跟 a 相同的記憶體位置
if(a === a.y) { }
if(a === a.y.y) { }

console.log(a.x); // 輸出 123
console.log(a.y.x); // 輸出 123
console.log(a.y.y.x); // 輸出 123
// 

在上面例子中我們知道了傳參考特性帶來的影響。但如果要複製一份全新的物件該怎麼做呢?請繼續看下去。

淺層複製(Shallow Copy)

淺層複製(Shallow Copy) 的方式僅複製物件的第一層屬性,如果物件的屬性值是物件,它們將保持作為參考的關係。以下是淺層複製的兩種方式。

1. 透過展開運算子(...

const obj1 = { name: '小明', age: 20 };
const obj2 = { ...obj1 };

obj2.age = 25;

console.log(obj1.age); // 輸出 20
console.log(obj2.age); // 輸出 25

2. 使用 Object.assign()

const obj1 = { name: '小明', age: 20 };
const obj2 = Object.assign({}, obj1);

obj2.age = 25;

console.log(obj1.age); // 輸出 20
console.log(obj2.age); // 輸出 25

深層複製(Deep Copy)

深層複製(Deep Copy) 是將物件中的所有屬性值(不論純值或物件類型)都複製新的一份到新物件中,也就是說**原物件和新物件間不會有屬性具有相同的參考。**以下是透過 JSON.parseJSON.stringify 來進行深層複製的方式。

const obj1 = { name: '小明家', area: { city: 'Tainan' } };
const obj2 = JSON.parse(JSON.stringify(obj1));

obj2.area.city = 'Taipei';

console.log(obj1.area.city); // 輸出: 'Tainan'
console.log(obj2.area.city); // 輸出: 'Taipei'

結語

JavaScript 中的物件傳參考特性使得在處理物件時需要格外小心。了解 淺層複製深層複製 的差別並知道何時、怎麼使用,是開發者必須要學會的課題。淺層複製適用於大部分情況,但如果需要完全獨立的物件副本,則需要使用深層複製。要注意的是大量使用深層複製可能導致效率問題(物件越多層時越明顯)。那麼今天就到這邊,我們明天見~


上一篇
[Day 19] 純值卻有屬性可用?關於「包裝物件(wrapper object)」
下一篇
[Day 21] 物件的「原型(Prototype)」是什麼?
系列文
複習 JavaScript 核心概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言